package com.huiquan.dyad.service;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.huiquan.dyad.dao.DyadInitDao;
import com.huiquan.dyad.dao.DyadStdDao;
import com.huiquan.dyad.domain.DyadPre;
import com.huiquan.dyad.domain.DyadStd;
import com.huiquan.dyad.domain.DyadStdOrder;
import com.huiquan.foundation.constant.SubmitStatus;
import com.huiquan.foundation.util.BusinessUtil;
import com.huiquan.framework.base.BaseService;
import com.huiquan.framework.base.ReturnData;
import com.huiquan.framework.constant.BaseContants;
import com.huiquan.framework.utils.CollectionUtil;
import com.huiquan.framework.utils.ReturnUtil;
import com.huiquan.symptom.dao.SymptomDao;
import com.huiquan.vocab.constant.VocabConstant;
import com.huiquan.vocab.dao.VocabDyadDao;
import com.huiquan.vocab.dao.VocabDyadRemoveDao;
import com.huiquan.vocab.dao.VocabElementDao;
import com.huiquan.vocab.dao.VocabElementLabelDao;
import com.huiquan.vocab.domain.VocabDyadRemove;
import com.huiquan.vocab.domain.VocabElementLabelResultDto;
import com.huiquan.vocab.service.VocabDyadInitService;

@Service
public class DyadInitService extends BaseService {

    @Autowired
    private DyadInitDao dyadInitDao;
    @Autowired
    private VocabDyadRemoveDao vocabDyadRemoveDao;
    @Autowired
    private VocabDyadDao vocabDyadDao;
    @Autowired
    private VocabElementDao vocabElementDao;
    @Autowired
    private SymptomDao symptomDao;
    @Autowired
    private VocabElementLabelDao vocabElementLabelDao;
    @Autowired
    private VocabDyadInitService vocabDyadInitService;

    private Map<String, Map<String, String>> replaceMap;
    private Set<String> deDecorateO;
    private Map<String, Map<String, String>> odeMap;
    private Map<String, Map<String, String>> ooMap;
    private Map<String, Map<String, String>> synonymyMap;
    private List<VocabDyadRemove> oOaRemove;
    private List<VocabDyadRemove> oInSRemove;
    private List<String> wrongPPList;
    private List<Map<String, String>> poMergeRoles;

    @Autowired
    private DyadStdDao dyadStdDao;

    /**
     * 根据最新的症状、元素和规则，抽取二元组到系统中；将未校验的二元组根据历史判定进行系统的判定
     *
     * @return
     */
    public ReturnData init() {
        if (!SubmitStatus.getSubmitRecords().contains(SubmitStatus.TYPE_DYAD_INIT)) {

            // 二元组初始化设置为运行中
            SubmitStatus.addSubmitRecords(SubmitStatus.TYPE_DYAD_INIT);
            // 抽取二元组到预备词中
            initDyadPre();

            // 将预备词维护到二元组表中
            initDyadByPre();

            // 根据历史的数据对未校验的二元组进行判定
            initFlag();
            SubmitStatus.removeSubmitRecords(SubmitStatus.TYPE_DYAD_INIT);

            LOGGER.info("Init dyad end!");
        }
        return ReturnUtil.success();
    }

    private void initDyadByPre() {
        // 将未校验的数据删除
        dyadInitDao.deleteUnchecked();

        // 将预备词根据类型和分词进行合并
        dyadInitDao.mergePre();

        // 根据合并的数据重新生成二元组的未校验数据
        initUncheckedDyadByPre();
    }

    /**
     * 根据合并的数据重新生成二元组的未校验数据
     */
    private void initUncheckedDyadByPre() {
        // 将未校验的数据加入到正式表中并维护例句
        dyadInitDao.insertUncheckedByPre();

        // 根据排序字段维护分页
        initPageByOrderVocab();

        // 初始化o+s的搜索词
        vocabDyadInitService.initOSSearch();
    }

    public void initPageByOrderVocab() {
        LOGGER.info("Init page start!");

        List<DyadStdOrder> stdOrderList = dyadInitDao.retrieveStdOrder();

        if (!stdOrderList.isEmpty()) {
            // 根据类型将排序数据分组
            Map<String, List<DyadStdOrder>> orderMap = new HashMap<>();
            String type = "";
            List<DyadStdOrder> tempList = new ArrayList<>();

            for (DyadStdOrder order : stdOrderList) {
                if (!type.equals(order.getType())) {
                    type = order.getType();
                    tempList = new ArrayList<>();
                    orderMap.put(type, tempList);
                }
                tempList.add(order);
            }

            // 将各个类型的排序字段转变为分页（如果一页不足20条数据，则从列表最后找数量互补的数据；该列表取出时已经过条数排序）
            List<DyadStdOrder> pageList = new ArrayList<>();
            DyadStdOrder order, tailOrder;
            int pageNo;
            for (String key : orderMap.keySet()) {
                pageNo = 1; // 记录页码
                tempList = orderMap.get(key);
                int tail = tempList.size() - 1; // 列表从后往前找页码互补数据的游标
                int pageCount;
                for (int i = 0; i <= tail; i++) {
                    order = tempList.get(i);
                    pageCount = order.getCnt();
                    String orderVocabulary = "'" + order.getOrderVocabulary() + "'";
                    // 如果数量少于20，而且尾部还有数据，则可以拼凑
                    while (pageCount < 20 && i < tail) {
                        tailOrder = tempList.get(tail);
                        pageCount += tailOrder.getCnt();
                        orderVocabulary += ",'" + tailOrder.getOrderVocabulary() + "'";
                        tail -= 1;
                    }
                    // 创建新的page
                    DyadStdOrder page = new DyadStdOrder();
                    page.setCnt(pageCount);
                    page.setFlag(order.getFlag());
                    page.setType(order.getType());
                    page.setOrderVocabulary(orderVocabulary);
                    page.setPageNo(pageNo);
                    pageList.add(page);

                    pageNo++;
                }
            }

            // 存入数据库
            dyadInitDao.batchInsertPage(pageList);
            LOGGER.info("Batch insert success!");
        }
        LOGGER.info("Init page end!");
    }

    /**
     * 对二元组分类处理：未校验的二元组直接更改；已校验的二元组判断后若有改变则给出提示列表 可以判别的规则有：(多de)+s/si，；p+p判别p+o
     */
    public void initFlag() {
        // 多个相同de的二元组必然为错误的，(单de)+s/si判别(多de)+s/si
        initDeFlag();

        // p+p判别p+o
        initPOFlag();
    }

    /**
     * p+o中所有的p组合起来是错误的p+p则该p+o为错误
     */
    private void initPOFlag() {
        // p+o中所有的p组合起来是错误的p+p则该p+o为错误
        dyadStdDao.initPOFlagByWrongPP();
    }

    /**
     * 针对未校验的二元组，多个相同de的二元组必然为错误的，(单de)+s/si判别(多de)+s/si
     */
    private void initDeFlag() {
        // 多个相同的de必然是错误的
        List<DyadStd> multiDeStds = dyadStdDao.retrieveUncheckedListByMultiDe();

        // 循环列表，对有重复de的二元组判定为错误并维护删除元素的字段
        for (DyadStd std : multiDeStds) {
            setFlagByMultiDe(std);
        }

        // 获取错误的(单de)+s/si和不是错误的(多de)+s/si
        initMultiDeWrong(VocabConstant.DYAD_S_DE);
        initMultiDeWrong(VocabConstant.DYAD_SI_DE);
    }

    /**
     * 用单个DE错误的数据来初始化对应多个DE的数据
     *
     * @param type
     */
    private void initMultiDeWrong(String type) {
        List<DyadStd> singleDeStds = dyadStdDao.retrieveWrongSingleDeList(type);
        List<DyadStd> multiDeStds = dyadStdDao.retrieveUncheckedMultiDeList(type);

        // 将多个DE对应数据根据de和非de的元素hash出来
        Map<String, List<DyadStd>> deMap = new HashMap<>();
        Map<String, List<DyadStd>> notDeMap = new HashMap<>();
        String[] stdArray, properties;
        for (DyadStd multiDeStd : multiDeStds) {
            stdArray = multiDeStd.getStdArray().substring(1).split(","); // 用元素标准词
            properties = multiDeStd.getPartPattern().substring(1).split(",");

            // 循环变量，将de和非de的二元组放入各自的map中
            for (int i = 0; i < properties.length; i++) {
                if (VocabConstant.ELEMENT_DEGREE.equals(properties[i])) {
                    List<DyadStd> temp = deMap.get(stdArray[i]);
                    if (temp == null) {
                        temp = new ArrayList<>();
                        deMap.put(stdArray[i], temp);
                    }
                    temp.add(multiDeStd);
                } else {
                    List<DyadStd> temp = notDeMap.get(stdArray[i]);
                    if (temp == null) {
                        temp = new ArrayList<>();
                        notDeMap.put(stdArray[i], temp);
                    }
                    temp.add(multiDeStd);
                }
            }
        }

        // 循环单个de的错误二元组，找到对应的多de二元组，将其设置为错误
        List<DyadStd> deList = new ArrayList<>();
        List<DyadStd> notDeList = new ArrayList<>();
        List<DyadStd> checkList = new ArrayList<>();
        for (DyadStd singleDeStd : singleDeStds) {
            stdArray = singleDeStd.getStdArray().substring(1).split(","); // 用元素标准词
            properties = singleDeStd.getPartPattern().substring(1).split(",");

            for (int i = 0; i < properties.length; i++) {
                if (VocabConstant.ELEMENT_DEGREE.equals(properties[i])) {
                    deList = deMap.get(stdArray[i]);
                } else {
                    notDeList = notDeMap.get(stdArray[i]);
                }
            }
            if (deList != null && notDeList != null) {
                checkList.clear();
                checkList.addAll(deList);
                checkList.retainAll(notDeList); // 将de和非de的元素都存在的二元组筛选出来
                if (!checkList.isEmpty()) {
                    for (DyadStd std : checkList) {
                        std.setFlag(BaseContants.FLAG_WRONG);
                        dyadStdDao.update(std);

                        deList.remove(std);
                        notDeList.remove(std);
                    }
                }
            }
        }
    }

    /**
     * 根据重复的de将二元组判定为错误的数据
     *
     * @param std
     */
    private void setFlagByMultiDe(DyadStd std) {
        String[] stdArrays = std.getStdArray().substring(1).split(",");
        String[] properties = std.getPartPattern().substring(1).split(",");
        List<String> words = new ArrayList<>();
        String property, word, combineS;

        // 循环属性和词语，记录de的词语，如果出现重复则维护正误值
        for (int i = 0; i < properties.length; i++) {
            property = properties[i];
            word = stdArrays[i];

            if (property.equals(VocabConstant.ELEMENT_DEGREE)) {
                if (words.contains(word)) {
                    // 判断是否需要更改数据
                    combineS = std.getPartPattern().replaceAll("de|s", "0");
                    combineS = combineS.replaceAll("oa|o", "1");
                    if (!BaseContants.FLAG_WRONG.equals(std.getFlag()) || !combineS.equals(std.getCombineS())) {
                        std.setFlag(BaseContants.FLAG_WRONG);
                        std.setCombineS(combineS);
                        dyadStdDao.update(std);
                    }
                } else {
                    words.add(word);
                }
            }
        }
    }

    /**
     * 初始化所有用到的数据
     */
    private void initDyadMap() {
        // 获取替换词语和替换属性Map
        replaceMap = getReplaceMap();

        // 可以修饰o的de
        deDecorateO = getDeDecorateO();

        // 获取所有的o+de二元组
        odeMap = getODeMap();

        // 获取所有的o+o的二元组
        ooMap = getOOMap();

        // 获取同义词对应map
        synonymyMap = getSynonmyMap();

        // 获取o+oa remove规则
        oOaRemove = getRemoveRuleByType("'o+oa'");

        // 获取'o+in' remove规则
        oInSRemove = getRemoveRuleByType("'o+in'");

        // 获取错误的P+P，不在错误的P+P中就默认为正确的
        wrongPPList = vocabDyadDao.retrieveWrongPPArray();

        // p+o合并规则
        poMergeRoles = dyadInitDao.retrievePOMerge();
    }

    public void initDyadPre() {

        // 查询需要抽取的出症状
        List<Map<String, String>> symptoms = symptomDao.retrieveDyadInitSymptomList();

        // 初始化用到的数据
        initDyadMap();

        // 需要保存的二元组
        List<DyadPre> addDyad = new ArrayList<>();

        LOGGER.info("开始抽取二元组,症状有:" + symptoms.size() + "条");
        for (Map<String, String> symptom : symptoms) {
            // 存放抽取出来的二元组
            List<DyadPre> dyadList = new ArrayList<>();

            String array = symptom.get("symptom_array");
            String partPattern = symptom.get("part_pattern");

            // 根据症状抽取出二元组
            dyadList.addAll(getDyadBySymptom(array, partPattern));

            // 所有的二元组添加相同的属性
            for (DyadPre dyad : dyadList) {
                dyad.setSymptomId(Long.parseLong(symptom.get("id")));
                dyad.setCnt(Integer.parseInt(symptom.get("cnt")));
                if (StringUtils.isBlank(dyad.getRemoveArray())) {
                    dyad.setRemoveArray("");
                }
                if (StringUtils.isBlank(dyad.getRemoveRa())) {
                    dyad.setRemoveRa("");
                }
                if (StringUtils.isBlank(dyad.getRemoveRp())) {
                    dyad.setRemoveRp("");
                }
                // 维护元素标准词
                String[] dyadArray = dyad.getArray().substring(1).split(",");
                String[] dyadPartpattern = dyad.getPartPattern().substring(1).split(",");
                // 有关于o的都 已经维护好了
                if (StringUtils.isBlank(dyad.getStdArray())) {
                    List<String> dyadStd = new ArrayList<>();
                    for (int i = 0; i < dyadArray.length; i++) {
                        dyadStd.add(synonymyMap.get(dyadPartpattern[i]).get(dyadArray[i]) == null ? dyadArray[i]
                                : synonymyMap.get(dyadPartpattern[i]).get(dyadArray[i]));
                    }
                    dyad.setStdArray(BusinessUtil.getStringFromListBySeparator(dyadStd, ","));
                    ;
                }
                // 维护排序字段
                String[] dyadStd = dyad.getStdArray().substring(1).split(",");
                // 排序字段in/o/si/s
                String tempIn = "";
                String tempO = "";
                String tempOa = "";
                String tempSi = "";
                String tempS = "";
                for (int i = 0; i < dyadPartpattern.length; i++) {
                    if ("in".equals(dyadPartpattern[i]) && StringUtils.isBlank(tempIn)) {
                        tempIn = dyadStd[i];
                    }
                    if ("o".equals(dyadPartpattern[i]) && StringUtils.isBlank(tempO)) {
                        tempO = dyadStd[i];
                    }
                    if ("oa".equals(dyadPartpattern[i]) && StringUtils.isBlank(tempO)) {
                        tempOa = dyadStd[i];
                    }
                    if ("si".equals(dyadPartpattern[i]) && StringUtils.isBlank(tempSi)) {
                        tempSi = dyadStd[i];
                    }
                    if ("s".equals(dyadPartpattern[i]) && StringUtils.isBlank(tempS)) {
                        tempS = dyadStd[i];
                    }
                }
                if (StringUtils.isNotBlank(tempIn)) {
                    dyad.setOrderVocabulary(tempIn);
                } else if (StringUtils.isNotBlank(tempO)) {
                    dyad.setOrderVocabulary(tempO);
                } else if (StringUtils.isNotBlank(tempOa)) {
                    dyad.setOrderVocabulary(tempOa);
                } else if (StringUtils.isNotBlank(tempSi)) {
                    dyad.setOrderVocabulary(tempSi);
                } else if (StringUtils.isNotBlank(tempS)) {
                    dyad.setOrderVocabulary(tempS);
                } else {
                    dyad.setOrderVocabulary("");
                }
                // 维护倒装de
                if (dyad.getType().contains("de")) {
                    List<String> sortStd = CollectionUtil.getListByArray(dyad.getStdArray().substring(1).split(","));
                    Collections.sort(sortStd, Collator.getInstance(java.util.Locale.CHINA));
                    dyad.setStdSynonym(BusinessUtil.getStringFromListBySeparator(sortStd, ","));
                } else {
                    dyad.setStdSynonym(dyad.getStdArray());
                }
            }
            addDyad.addAll(dyadList);
        }
        dyadInitDao.deleteAllPre();
        // 存到临时表中
        dyadInitDao.batchInsertInitPre(addDyad);
        LOGGER.info("二元组抽取结束！");

    }

    /**
     * 根据单条症状抽取二元组,并维护标准词
     *
     * @param array
     * @param partPattern
     * @return
     */
    public List<DyadPre> getDyadPreBySymptom(String array, String partPattern) {
        // 如果有一个用到的变量为空,需要初始化,用到的数据
        if (replaceMap == null || deDecorateO == null || odeMap == null || ooMap == null || synonymyMap == null
                || oOaRemove == null || oInSRemove == null || wrongPPList == null || poMergeRoles == null) {
            initDyadMap();
        }
        // 存放抽取出来的二元组
        List<DyadPre> dyadList = new ArrayList<>();
        dyadList.addAll(getDyadBySymptom(array, partPattern));
        // 所有的二元组添加相同的属性
        for (DyadPre dyad : dyadList) {
            // 维护元素标准词
            String[] dyadArray = dyad.getArray().substring(1).split(",");
            String[] dyadPartpattern = dyad.getPartPattern().substring(1).split(",");
            // 有关于o的都 已经维护好了
            if (StringUtils.isBlank(dyad.getStdArray())) {
                List<String> dyadStd = new ArrayList<>();
                for (int i = 0; i < dyadArray.length; i++) {
                    dyadStd.add(synonymyMap.get(dyadPartpattern[i]).get(dyadArray[i]) == null ? dyadArray[i]
                            : synonymyMap.get(dyadPartpattern[i]).get(dyadArray[i]));
                }
                dyad.setStdArray(BusinessUtil.getStringFromListBySeparator(dyadStd, ","));
            }
            // 维护倒装de
            if (dyad.getType().contains("de")) {
                List<String> sortStd = CollectionUtil.getListByArray(dyad.getStdArray().substring(1).split(","));
                Collections.sort(sortStd, Collator.getInstance(java.util.Locale.CHINA));
                dyad.setStdSynonym(BusinessUtil.getStringFromListBySeparator(sortStd, ","));
            } else {
                dyad.setStdSynonym(dyad.getStdArray());
            }
        }
        return dyadList;
    }

    /**
     * 根据单条症状抽取二元组
     *
     * @return
     */
    private List<DyadPre> getDyadBySymptom(String array, String partPattern) {
        // 存放抽取出来的二元组
        List<DyadPre> dyadList = new ArrayList<>();

        String[] wordArray = array.substring(1).split(",");
        String[] partPatternArray = partPattern.substring(1).split(",");
        List<DyadPre> side = new ArrayList<>();
        List<DyadPre> oDe = new ArrayList<>();
        List<DyadPre> sde = new ArrayList<>();
        List<DyadPre> pp = new ArrayList<>();
        List<DyadPre> po = new ArrayList<>();
        List<DyadPre> oo = new ArrayList<>();
        List<DyadPre> oIn = new ArrayList<>();
        List<DyadPre> oS = new ArrayList<>();
        List<DyadPre> inS = new ArrayList<>();

        // 获取二元组元素对应的标准词
        String[] std = null;
        // 处理替换词语和替换属性
        Map<String, String> replaceResult = replaceVocab(replaceMap, wordArray, partPatternArray);
        if (replaceResult != null && replaceResult.size() > 0) {
            if(!StringUtils.equals(array,replaceResult.get("array")) || !StringUtils.equals(partPattern,replaceResult.get("partPattern"))){
                array = replaceResult.get("array");
                partPattern = replaceResult.get("partPattern");
                wordArray = array.substring(1).split(",");
                partPatternArray = partPattern.substring(1).split(",");
            }
        }
        // 维护好二元组分词的同义词标准词
        std = getStdArray(wordArray, partPatternArray, synonymyMap);

        // 抽取si+de单个和多个都抽取
        if (checkProperty(partPattern, "si,de")) {
            side = extractDe("si", wordArray, partPatternArray);
            dyadList.addAll(side);
        }
        // o+de直接抽取多个 能被o带走的de
        if (checkProperty(partPattern, "o,de")) {
            oDe = extractODe(wordArray, partPatternArray, deDecorateO, std);
            dyadList.addAll(oDe);
        }
        // s+de 除去已经判断修饰o的de,再抽取s+de (先要抽取单个de,再抽取多个进行校验(抽取时,全部抽取在之后进行校验))
        if (checkProperty(partPattern, "s,de")) {
            sde = extractSDe(wordArray, partPatternArray, oDe, odeMap, synonymyMap.get("de"));
            dyadList.addAll(sde);
        }

        // p+p 连续抽取整个p,p,p
        if (checkProperty(partPattern, "p")) {
            pp = extractP(wordArray, partPatternArray);
            dyadList.addAll(pp);
        }

        // 抽取p+o,相邻的p相邻的p+(单独o)或(单独o)+p
        if (checkProperty(partPattern, "p,o")) {
            po = extractPO(wordArray, partPatternArray, std, wrongPPList);
            dyadList.addAll(po);

            // p+o抽取完后p+o合并成o(同时拥有按合成结果)
            // 合并完把std转变为二元组的std为了合并同义词
            Map<String, String> mergeResult = mergePO(array, partPattern, std, poMergeRoles);
            if (mergeResult != null && mergeResult.size() > 0) {
                array = mergeResult.get("array");
                partPattern = mergeResult.get("partPattern");
                wordArray = array.substring(1).split(",");
                partPatternArray = partPattern.substring(1).split(",");
                std = mergeResult.get("std").substring(1).split(",");
            }
        }

        // 保存还剩下o的下标
        List<Integer> oWordIndex = new ArrayList<>();
        // o+o抽取症状中所有的o
        // 抽取o+o 如果抽取的o+o 只有一个o 就用这个o抽取o+s
        if (checkProperty(partPattern, "o")) {
            oo = extractOO(wordArray, partPatternArray, synonymyMap, oWordIndex, oOaRemove, std);
            // 如果 还剩多个o就加入二元组校验
            if (oo != null && oo.size() > 0) {
                String[] arr = oo.get(0).getArray().substring(1).split(",");
                if (arr.length > 1) {
                    // 加入二元组校验
                    dyadList.addAll(oo);
                }
            }
        }

        // in 不抽取(需要remove)
        if (checkProperty(partPattern, "in")) {
            // 有o+oa 经过remove了
            if (oo != null && oo.size() > 0) {
                oIn = extractOIn(wordArray, partPatternArray, synonymyMap, oo.get(0), oWordIndex, oInSRemove, std);
                dyadList.addAll(oIn);
            }
            // 抽取in+s
            if (checkProperty(partPattern, "in,s")) {
                inS = extractInS(wordArray, partPatternArray);
                dyadList.addAll(inS);
            }
        }

        // o+s抽取 根据正确的o+o的核心词抽取o+s
        if (checkProperty(partPattern, "s")) {
            // 有o+o 经过remove了
            if (oo != null && oo.size() > 0) {
                String[] arr = oo.get(0).getArray().substring(1).split(",");
                // 有o+o需要经过核心词判断
                if (arr.length > 1) {
                    // 没有校验过o+o的核心词的不抽取,错误的o+o也不抽取o+s
                    oS = extractOS(wordArray, partPatternArray, synonymyMap, oo.get(0), oWordIndex, ooMap, std);
                } else {
                    // 只有一个o 直接抽取o+s
                    oS = extractOS(wordArray, partPatternArray, oo.get(0), oWordIndex, std);
                }
                dyadList.addAll(oS);
            }
        }
        // o+s中单独的si也要抽取到o+s中
        if (partPattern.contains("si")) {
            for (int i = 0; i < partPatternArray.length; i++) {
                if ("si".equals(partPatternArray[i])) {
                    DyadPre pre = new DyadPre();
                    pre.setArray("," + wordArray[i] + ",");
                    pre.setPartPattern("," + partPatternArray[i] + ",");
                    pre.setStdArray("," + std[i] + ",");
                    pre.setType("o+s");
                    dyadList.add(pre);
                }
            }
        }
        return dyadList;
    }

    /**
     * 直接抽取in+s
     *
     * @param wordArray
     * @param partPatternArray
     * @return
     */
    private List<DyadPre> extractInS(String[] wordArray, String[] partPatternArray) {
        List<String> inSArray = new ArrayList<>();
        List<String> inSPartPattern = new ArrayList<>();
        List<DyadPre> rtn = new ArrayList<>();
        for (int i = 0; i < wordArray.length; i++) {
            if ("in".equals(partPatternArray[i]) || "s".equals(partPatternArray[i])) {
                inSArray.add(wordArray[i]);
                inSPartPattern.add(partPatternArray[i]);
            }
        }
        DyadPre pre = new DyadPre();
        pre.setArray(BusinessUtil.getStringFromListBySeparator(inSArray, ","));
        pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(inSPartPattern, ","));
        pre.setType("in+s");
        rtn.add(pre);
        return rtn;
    }

    private List<VocabDyadRemove> getRemoveRuleByType(String type) {
        Map<String, Object> param1 = new HashMap<>();
        param1.clear();
        param1.put("removeFlag", BaseContants.FLAG_YES);
        param1.put("types", type);
        param1.put("orderStr", "CHAR_LENGTH(part_pattern) desc");
        List<VocabDyadRemove> firstRemoveList = vocabDyadRemoveDao.retrieveList(param1);
        return firstRemoveList;
    }

    /**
     * 多个o 需要经过o+o的核心词校验,若o+o是错误的二元组则不抽取o+s ,若是正确的o+o则根据核心词抽取, 若o+o未校验,则不抽取o+s
     *
     * @param wordArray
     * @param partPatternArray
     * @param synonymyMap
     * @param DyadPre
     * @param oWordIndex
     * @param ooMap
     * @return
     */
    private List<DyadPre> extractOS(String[] wordArray, String[] partPatternArray,
                                    Map<String, Map<String, String>> synonymyMap, DyadPre oo, List<Integer> oWordIndex,
                                    Map<String, Map<String, String>> ooMap, String[] std) {
        List<DyadPre> rtn = new ArrayList<>();
        // o在原症状下的下标
        if (oo != null && oWordIndex != null && oWordIndex.size() > 0) {
            // o+o是全部抽取,所以只有一条
            String ooArray = oo.getArray();
            String ooPartPattern = oo.getPartPattern();
            String ooStd = oo.getStdArray();

            // 如果已校验该组o+o会直接到标准词下,所以不需要进行元素标准词处理.
            if (ooMap.get(ooArray + "-" + ooPartPattern) != null) {
                // 已校验的o+o 找到核心词
                Map<String, String> ooKeyWord = ooMap.get(ooArray + "-" + ooPartPattern);
                String[] ooStdArr = ooKeyWord.get("array").substring(1).split(",");
                String[] ooStdFlag = ooKeyWord.get("combine_s").substring(1).split(",");
                // 获取核心词 从最后一个开始匹配
                List<Integer> combineSIndex = new ArrayList<>();
                // 记录下核心词的位置
                for (int i = (ooStdArr.length - 1); i >= (ooStdArr.length - ooStdFlag.length); i--) {
                    if ("1".equals(ooStdFlag[i - (ooStdArr.length - ooStdFlag.length)])) {
                        combineSIndex.add(i);
                    }
                }
                List<String> oSArray = new ArrayList<>();
                List<String> oSPartPattern = new ArrayList<>();
                List<String> oSStd = new ArrayList<>();

                // 二元组o+o的词
                String[] oArray = ooArray.substring(1).split(",");
                String[] oPartPattern = ooPartPattern.substring(1).split(",");
                String[] oStd = ooStd.substring(1).split(",");
                // 抽取o+s
                outter:
                for (int i = 0; i < wordArray.length; i++) {
                    // 添加o 和 oa remove后的结果
                    for (int j = 0; j < oWordIndex.size(); j++) {
                        // 判断该位置是不是remove留下的o
                        if (i == oWordIndex.get(j)) {
                            // 判断该位置是不是核心词
                            if (combineSIndex.contains(j)) {
                                oSArray.add(oArray[j]);
                                oSPartPattern.add(oPartPattern[j]);
                                oSStd.add(oStd[j]);
                                continue outter;
                            }
                        }
                    }
                    if ("s".equals(partPatternArray[i])) {
                        oSArray.add(wordArray[i]);
                        oSPartPattern.add(partPatternArray[i]);
                        oSStd.add(std[i]);
                    }

                }
                DyadPre pre = new DyadPre();
                pre.setArray(BusinessUtil.getStringFromListBySeparator(oSArray, ","));
                pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(oSPartPattern, ","));
                pre.setStdArray(BusinessUtil.getStringFromListBySeparator(oSStd, ","));
                pre.setType("o+s");
                rtn.add(pre);
                return rtn;
            } else {
                // oo没有校验或者为错误的二元组,不抽取o+s
                return rtn;
            }
        }

        return rtn;
    }

    /**
     * 单个o抽取o+s
     *
     * @param wordArray
     * @param partPatternArray
     * @param synonymyMap
     * @param DyadPre
     * @param oWordIndex
     * @return
     */
    private List<DyadPre> extractOS(String[] wordArray, String[] partPatternArray, DyadPre DyadPre,
                                    List<Integer> oWordIndex, String[] std) {
        List<DyadPre> rtn = new ArrayList<>();
        // 根据o+oa remove结果替换症状中的o
        String[] oArray = DyadPre.getArray().substring(1).split(",");
        String[] oPartPattern = DyadPre.getPartPattern().substring(1).split(",");
        String[] oStd = DyadPre.getStdArray().substring(1).split(",");

        List<String> oSArray = new ArrayList<>();
        List<String> oSPartPattern = new ArrayList<>();
        List<String> oSStd = new ArrayList<>();

        outter:
        for (int i = 0; i < wordArray.length; i++) {
            // 添加o 和 oa remove后的结果
            for (int j = 0; j < oWordIndex.size(); j++) {
                if (i == oWordIndex.get(j)) {
                    oSArray.add(oArray[j]);
                    oSPartPattern.add(oPartPattern[j]);
                    oSStd.add(oStd[j]);
                    continue outter;
                }
            }
            if ("s".equals(partPatternArray[i])) {
                oSArray.add(wordArray[i]);
                oSPartPattern.add(partPatternArray[i]);
                oSStd.add(std[i]);
            }
        }
        DyadPre pre = new DyadPre();
        pre.setArray(BusinessUtil.getStringFromListBySeparator(oSArray, ","));
        pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(oSPartPattern, ","));
        pre.setStdArray(BusinessUtil.getStringFromListBySeparator(oSStd, ","));
        pre.setType("o+s");
        rtn.add(pre);
        return rtn;
    }

    private String[] getStdArray(String[] wordArray, String[] partPatternArray,
                                 Map<String, Map<String, String>> synonymyMap) {
        List<String> std = new ArrayList<>();
        for (int i = 0; i < wordArray.length; i++) {
            std.add(synonymyMap.get(partPatternArray[i]).get(wordArray[i]) != null
                    ? synonymyMap.get(partPatternArray[i]).get(wordArray[i]) : wordArray[i]);
        }
        return std.toArray(new String[0]);
    }

    private List<DyadPre> extractOIn(String[] wordArray, String[] partPatternArray,
                                     Map<String, Map<String, String>> synonymyMap, DyadPre DyadPre, List<Integer> oWordIndex,
                                     List<VocabDyadRemove> oInSRemove, String[] std) {
        // 根据o+oa remove结果替换症状中的o
        String[] oArray = DyadPre.getArray().substring(1).split(",");
        String[] oPartPattern = DyadPre.getPartPattern().substring(1).split(",");
        String[] oStd = DyadPre.getStdArray().substring(1).split(",");

        List<String> oInSArray = new ArrayList<>();
        List<String> oInSPartPattern = new ArrayList<>();
        List<String> oInSStd = new ArrayList<>();

        outter:
        for (int i = 0; i < wordArray.length; i++) {
            // 添加o 和 oa remove后的结果
            for (int j = 0; j < oWordIndex.size(); j++) {
                if (i == oWordIndex.get(j)) {
                    oInSArray.add(oArray[j]);
                    oInSPartPattern.add(oPartPattern[j]);
                    oInSStd.add(oStd[j]);
                    continue outter;
                }
            }
            if ("in".equals(partPatternArray[i])) {
                oInSArray.add(wordArray[i]);
                oInSPartPattern.add(partPatternArray[i]);
                oInSStd.add(std[i]);
            }
        }
        // 获取o+in remove规则
        Map<String, String> rtn = dealRemove(BusinessUtil.getStringFromListBySeparator(oInSArray, ","),
                BusinessUtil.getStringFromListBySeparator(oInSPartPattern, ","), oInSRemove, synonymyMap, oWordIndex,
                BusinessUtil.getStringFromListBySeparator(oInSStd, ","));
        List<DyadPre> pres = new ArrayList<>();
        if (rtn != null && rtn.size() > 0) {
            DyadPre pre = new DyadPre();
            pre.setPartPattern(rtn.get("partPattern"));
            pre.setArray(rtn.get("array"));
            pre.setStdArray(rtn.get("std"));
            pre.setRemoveArray(rtn.get("remove_array") != null ? rtn.get("remove_array") : "");
            pre.setRemoveRa(rtn.get("remove_ra") != null ? rtn.get("remove_ra") : "");
            pre.setRemoveRp(rtn.get("remove_rp") != null ? rtn.get("remove_rp") : "");
            pre.setType("o+in");
            if (pre.getPartPattern().contains("o") && pre.getPartPattern().contains("in")) {
                pres.add(pre);
            }
        }
        return pres;
    }

    /**
     * 抽取o+o 抽取完后进行remove
     *
     * @param wordArray
     * @param partPatternArray
     * @param oOaRemove
     * @return
     */
    private List<DyadPre> extractOO(String[] wordArray, String[] partPatternArray,
                                    Map<String, Map<String, String>> synonymy, List<Integer> oWordIndex, List<VocabDyadRemove> oOaRemove,
                                    String[] std) {
        List<String> ooList = new ArrayList<>();
        List<String> ooPartList = new ArrayList<>();
        List<String> ooStdList = new ArrayList<>();

        for (int i = 0; i < wordArray.length; i++) {
            if ("oa".equals(partPatternArray[i]) || "o".equals(partPatternArray[i])) {
                ooList.add(wordArray[i]);
                ooPartList.add(partPatternArray[i]);
                ooStdList.add(std[i]);
                oWordIndex.add(i);
            }
        }

        List<DyadPre> pres = new ArrayList<>();
        // 大于1个o的时候需要进行remove
        if (ooList.size() > 1) {
            Map<String, String> rtn = dealRemove(BusinessUtil.getStringFromListBySeparator(ooList, ","),
                    BusinessUtil.getStringFromListBySeparator(ooPartList, ","), oOaRemove, synonymy, oWordIndex,
                    BusinessUtil.getStringFromListBySeparator(ooStdList, ","));
            if (rtn != null && rtn.size() > 0) {
                DyadPre pre = new DyadPre();
                pre.setPartPattern(rtn.get("partPattern"));
                pre.setArray(rtn.get("array"));
                pre.setStdArray(rtn.get("std"));
                pre.setRemoveArray(rtn.get("remove_array") != null ? rtn.get("remove_array") : "");
                pre.setRemoveRa(rtn.get("remove_ra") != null ? rtn.get("remove_ra") : "");
                pre.setRemoveRp(rtn.get("remove_rp") != null ? rtn.get("remove_rp") : "");
                pre.setType("o+o");
                pres.add(pre);
            }
        } else {
            DyadPre pre = new DyadPre();
            pre.setPartPattern(BusinessUtil.getStringFromListBySeparator(ooPartList, ","));
            pre.setArray(BusinessUtil.getStringFromListBySeparator(ooList, ","));
            pre.setStdArray(BusinessUtil.getStringFromListBySeparator(ooStdList, ","));

            pres.add(pre);
        }
        return pres;
    }

    /**
     * 根据类型和remove规则进行remove remove 属性不能间隔
     *
     * @param type
     * @param ooList
     * @param ooPartList
     * @param firstRemoveList
     */
    private Map<String, String> dealRemove(String array, String partPattern, List<VocabDyadRemove> firstRemoveList,
                                           Map<String, Map<String, String>> synonymy, List<Integer> oWordIndex, String std) {
        Map<String, String> rtn = new HashMap<>();
        String tempArray = "";
        String tempPartPattern = "";

        // 经过规则合并后没有变化了出循环
        while (!StringUtils.equals(tempArray, array) && !StringUtils.equals(tempPartPattern, partPattern)) {
            // 记录进循环时的分词和属性
            tempArray = array;
            tempPartPattern = partPattern;

            // 进行规则循环合并
            for (VocabDyadRemove remove : firstRemoveList) {
                String[] wordArray = array.substring(1).split(",");
                String[] partPatternArray = partPattern.substring(1).split(",");
                String[] stdArray = std.substring(1).split(",");
                String[] removeArray = remove.getArray().substring(1).split(",");
                String[] removePartPattern = remove.getPartPattern().substring(1).split(",");
                String[] resultArray = remove.getResultArray().substring(1).split(",");
                String[] resultPattern = remove.getResultPattern().substring(1).split(",");
                // 获取remove匹配到的词语的下标
                List<Integer> removeIndex = new ArrayList<>();
                int j = 0;
                boolean beginFlag = false;
                // 如果规则数组小于等于症状数组才进行处理
                if (wordArray.length >= removeArray.length) {
                    // 循环获取匹配上的下标
                    remove:
                    for (int i = 0; i < removeArray.length; ) {
                        for (; j < wordArray.length; j++) {
                            // 元素同义词的标准词相同
                            // o ,oa 忽略属性
                            if (("oa".equals(removePartPattern[i]) || "o".equals(removePartPattern[i]))
                                    && "oa".equals(partPatternArray[j]) || "o".equals(partPatternArray[j])) {
                                if (StringUtils.equals(
                                        synonymy.get(partPatternArray[j]).get(wordArray[j]) == null ? wordArray[j]
                                                : synonymy.get(partPatternArray[j]).get(wordArray[j]),
                                        synonymy.get(removePartPattern[i]).get(removeArray[i]) == null ? removeArray[i]
                                                : synonymy.get(removePartPattern[i]).get(removeArray[i]))) {
                                    removeIndex.add(j);
                                    j++;
                                    beginFlag = true;
                                    break;
                                } else {
                                    // 不相同则重新开始
                                    if (beginFlag) {
                                        beginFlag = false;
                                        i = 0;
                                        continue remove;
                                    }
                                }

                            } else {
                                // 如果不是o和oa则需要比较属性
                                if (removePartPattern[i].equals(partPatternArray[j]) && StringUtils.equals(
                                        synonymy.get(partPatternArray[j]).get(wordArray[j]) == null ? wordArray[j]
                                                : synonymy.get(partPatternArray[j]).get(wordArray[j]),
                                        synonymy.get(removePartPattern[i]).get(removeArray[i]) == null ? removeArray[i]
                                                : synonymy.get(removePartPattern[i]).get(removeArray[i]))) {
                                    removeIndex.add(j);
                                    j++;
                                    beginFlag = true;
                                    break;
                                } else {
                                    // 不相同则重新开始
                                    if (beginFlag) {
                                        beginFlag = false;
                                        i = 0;
                                        continue remove;
                                    }
                                }
                            }
                        }
                        i++;
                    }
                }
                // 规则匹配成功
                if (removeArray.length == removeIndex.size()) {
                    // 记录remove规则和结果和属性
                    if (rtn.get("remove_array") != null && rtn.get("remove_ra") != null
                            && rtn.get("remove_rp") != null) {
                        rtn.put("remove_array", rtn.get("remove_array") + BusinessUtil
                                .getStringFromListBySeparator(CollectionUtil.getListByArray(removeArray), ",") + "|");
                        rtn.put("remove_ra", rtn.get("remove_ra") + BusinessUtil
                                .getStringFromListBySeparator(CollectionUtil.getListByArray(resultArray), ",") + "|");
                        rtn.put("remove_rp", rtn.get("remove_rp") + BusinessUtil
                                .getStringFromListBySeparator(CollectionUtil.getListByArray(resultPattern), ",") + "|");
                    } else {
                        rtn.put("remove_array", BusinessUtil
                                .getStringFromListBySeparator(CollectionUtil.getListByArray(removeArray), ",") + "|");
                        rtn.put("remove_ra", BusinessUtil
                                .getStringFromListBySeparator(CollectionUtil.getListByArray(resultArray), ",") + "|");
                        rtn.put("remove_rp", BusinessUtil
                                .getStringFromListBySeparator(CollectionUtil.getListByArray(resultPattern), ",") + "|");
                    }

                    List<String> wordList = CollectionUtil.getListByArray(wordArray);
                    List<String> partPatternList = CollectionUtil.getListByArray(partPatternArray);
                    List<String> stdList = CollectionUtil.getListByArray(stdArray);

                    // 找到被remove掉的词
                    int k = 0;
                    List<Integer> removeWordIndex = new ArrayList<>();
                    for (int i = 0; i < removeArray.length; i++) {
                        if (k < resultArray.length) {
                            if (!removeArray[i].equals(resultArray[k])) {
                                removeWordIndex.add(i);
                            } else {
                                k++;
                            }
                        } else {
                            removeWordIndex.add(i);
                        }
                    }
                    int m = 0;
                    // 替换属性
                    for (int i = 0; i < removeIndex.size(); i++) {
                        // 不是remove的词进行属性替换
                        if (!removeWordIndex.contains(i)) {
                            partPatternList.set((int) removeIndex.get(i), resultPattern[m]);
                            m++;
                        }
                    }
                    // remove该词
                    for (int i = (removeWordIndex.size() - 1); i >= 0; i--) {
                        wordList.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
                        partPatternList.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
                        stdList.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
                        // 如果是o+in+s的remove保留o的index用于o+s抽取 , o+oa
                        // remove时候remove o
                        if (!remove.getType().contains("in")) {
                            oWordIndex.remove((int) removeIndex.get((int) removeWordIndex.get(i)));
                        }
                        removeWordIndex.remove(i);
                    }
                    array = BusinessUtil.getStringFromListBySeparator(wordList, ",");
                    partPattern = BusinessUtil.getStringFromListBySeparator(partPatternList, ",");
                    std = BusinessUtil.getStringFromListBySeparator(stdList, ",");
                }
            }
        }
        rtn.put("array", array);
        rtn.put("partPattern", partPattern);
        rtn.put("std", std);

        return rtn;
    }

    /**
     * 获取同义词~同义词o ,oa若判定为相同,属性可以忽略
     *
     * @return
     */
    private Map<String, Map<String, String>> getSynonmyMap() {
        // 忽略o 和 oa的同义词,如果他们两个相同的话
        List<Map<String, String>> synonymys = dyadInitDao.retrieveDyadSynonymy();
        Map<String, Map<String, String>> synonymyMap = new HashMap<>();
        for (Map<String, String> synonymy : synonymys) {
            String property = synonymy.get("property");
            String word = synonymy.get("word");
            String std = synonymy.get("std");
            if (synonymyMap.get(property) != null) {
                synonymyMap.get(property).put(word, std);
            } else {
                Map<String, String> syn = new HashMap<>();
                syn.put(word, std);
                synonymyMap.put(property, syn);
            }
        }
        return synonymyMap;
    }

    private Map<String, Map<String, String>> getODeMap() {
        // 查询所有的o+de二元组
        List<Map<String, String>> odeAll = dyadInitDao.retrieveOdeCombine();
        Map<String, Map<String, String>> rtn = new HashMap<>();
        for (Map<String, String> ode : odeAll) {
            rtn.put(ode.get("array") + "-" + ode.get("part_pattern"), ode);
        }
        return rtn;
    }

    private Map<String, Map<String, String>> getOOMap() {
        // 查询所有的o+o二元组
        List<Map<String, String>> ooAll = dyadInitDao.retrieveOOCombine();
        Map<String, Map<String, String>> rtn = new HashMap<>();
        for (Map<String, String> oo : ooAll) {
            rtn.put(oo.get("array") + "-" + oo.get("part_pattern"), oo);
        }
        return rtn;
    }

    /**
     * 抽取s+de 除去已经判断修饰o的de,再抽取s+de
     *
     * @param wordArray
     * @param partPatternArray
     * @param ode
     * @param odeMap
     * @return
     */
    private List<DyadPre> extractSDe(String[] wordArray, String[] partPatternArray, List<DyadPre> odeList,
                                     Map<String, Map<String, String>> odeMap, Map<String, String> deSynonmy) {
        List<DyadPre> rtn = new ArrayList<>();
        if (odeList != null && odeList.size() > 0) {
            // o+de是全部抽取,所以只有一条
            String oDeArray = odeList.get(0).getArray();
            String oDePartPattern = odeList.get(0).getPartPattern();

            // 存在o+de的情况,就必须先判断完o+de ,再抽取s+de不然不抽取
            // 判断是否属性和词语都一样
            if (odeMap.get(oDeArray + "-" + oDePartPattern) != null) {
                // 已校验的o+de 看看已经使用了的de
                Map<String, String> ode = odeMap.get(oDeArray + "-" + oDePartPattern);
                // 如果flag= 0 正确 ---> 所有的o和de都能被带走
                String flag = ode.get("flag");
                String[] dePart = ode.get("part_pattern").substring(1).split(",");
                String[] deArray = ode.get("array").substring(1).split(",");
                String[] deFlag = ode.get("combine_s").substring(1).split(",");

                String array = "";
                String partPattern = "";
                if (StringUtils.equals(flag, "0")) {
                    // 都可以被带走
                    // 去除被o带走的de
                    Map<String, String> removeResult = removeDeByO(wordArray, partPatternArray,
                            oDeArray.substring(1).split(","), oDePartPattern.substring(1).split(","));
                    if (removeResult != null && removeResult.size() > 0) {
                        array = removeResult.get("array");
                        partPattern = removeResult.get("partPattern");
                    }
                } else {
                    // 有不能被带走的de
                    // 根据标准词查找可以带走的de
                    List<String> deS = new ArrayList<>();
                    List<String> deSPart = new ArrayList<>();
                    for (int i = 0; i < wordArray.length; i++) {
                        if ("de".equals(partPatternArray[i]) || "s".equals(partPatternArray[i])) {
                            deS.add(wordArray[i]);
                            deSPart.add(partPatternArray[i]);
                        }
                    }
                    // 可以被带走的下标
                    TreeSet<Integer> deSIndex = new TreeSet<Integer>();
                    // 循环可以被带走的de的元素标准词
                    for (int i = 0; i < deArray.length; i++) {
                        if ("de".equals(dePart[i]) && "1".equals(deFlag[i])) {
                            // 循环记录被带走的下标
                            for (int j = 0; j < deS.size(); j++) {
                                // 标准词进行比较
                                if (StringUtils.equals(dePart[i], deSPart.get(j)) && StringUtils.equals(
                                        deSynonmy.get(deArray[i]) == null ? deArray[i] : deSynonmy.get(deArray[i]),
                                        deSynonmy.get(deS.get(j)) == null ? deS.get(j) : deSynonmy.get(deS.get(j)))) {
                                    deSIndex.add(j);
                                }
                            }
                        }
                    }
                    for (int i = 0; i < deSIndex.size(); ) {
                        int index = deSIndex.pollLast();
                        deS.remove(index);
                        deSPart.remove(index);
                    }
                    array = BusinessUtil.getStringFromListBySeparator(deS, ",");
                    partPattern = BusinessUtil.getStringFromListBySeparator(deSPart, ",");
                }
                rtn = extractDe("s", array.substring(1).split(","), partPattern.substring(1).split(","));
            }
        } else {
            // 不存在o+de的情况全部抽取s+de
            rtn = extractDe("s", wordArray, partPatternArray);
        }
        return rtn;
    }

    private Map<String, String> removeDeByO(String[] wordArray, String[] partPatternArray, String[] oDeArray,
                                            String[] oDePartPattern) {
        TreeSet<Integer> removeIndex = new TreeSet<Integer>();
        for (int i = 0; i < oDeArray.length; i++) {
            for (int j = 0; j < wordArray.length; j++) {
                if (StringUtils.equals(wordArray[j], oDeArray[i])
                        && StringUtils.equals(partPatternArray[j], oDePartPattern[i])) {
                    removeIndex.add(j);
                    break;
                }
            }
        }
        List<String> wordList = CollectionUtil.getListByArray(wordArray);
        List<String> partPatternList = CollectionUtil.getListByArray(partPatternArray);
        for (int i = 0; i < removeIndex.size(); ) {
            int index = removeIndex.pollLast();
            wordList.remove(index);
            partPatternList.remove(index);
        }
        Map<String, String> rtn = new HashMap<>();
        rtn.put("array", BusinessUtil.getStringFromListBySeparator(wordList, ","));
        rtn.put("partPattern", BusinessUtil.getStringFromListBySeparator(partPatternList, ","));
        return rtn;
    }

    /**
     * 查找可以修饰o的de
     *
     * @return
     */
    private Set<String> getDeDecorateO() {
        // 初始化修饰o的de的表
        vocabElementLabelDao.init();
        Map<String, Object> param = new HashMap<>();
        param.put("isDecorateO", 1);
        Set<String> de = new HashSet<>();
        List<VocabElementLabelResultDto> labelResult = vocabElementLabelDao.retrieveResultList(param);
        for (VocabElementLabelResultDto result : labelResult) {
            de.add(result.getElement());
        }
        return de;
    }

    /**
     * 抽取o+de 所有de与o 整个抽取 de,o,de,de,oa,de,s ----> de,o,de,de,oa,de
     *
     * @param wordArray
     * @param partPatternArray
     * @return
     */
    private static List<DyadPre> extractODe(String[] wordArray, String[] partPatternArray, Set<String> deDecorateO,
                                            String[] std) {
        List<String> deOArrayList = new ArrayList<>();
        List<String> deOPartList = new ArrayList<>();
        List<DyadPre> rtn = new ArrayList<>();
        DyadPre ode = new DyadPre();
        for (int i = 0; i < wordArray.length; i++) {
            if ("de".equals(partPatternArray[i])) {
                if (deDecorateO.contains(std[i])) {
                    deOArrayList.add(wordArray[i]);
                    deOPartList.add(partPatternArray[i]);
                }
            } else if ("o".equals(partPatternArray[i]) || "oa".equals(partPatternArray[i])) {
                deOArrayList.add(wordArray[i]);
                deOPartList.add(partPatternArray[i]);
            }
        }
        ode.setArray(BusinessUtil.getStringFromListBySeparator(deOArrayList, ","));
        ode.setPartPattern(BusinessUtil.getStringFromListBySeparator(deOPartList, ","));
        ode.setType("o+de");
        // 如果de都不能修饰o则没有o+de二元组
        if (deOPartList.contains("de") && (deOPartList.contains("o") || deOPartList.contains("oa"))) {
            rtn.add(ode);
        }
        return rtn;
    }

    /**
     * 抽取o+de 所有de与o 整个抽取 de,o,de,de,oa ----> de,o,de,de 和 de,de,de,oa
     *
     * @param wordArray
     * @param partPatternArray
     * @return
     */
    @Deprecated
    private static List<DyadPre> extractODeByO(String[] wordArray, String[] partPatternArray, Set<String> deDecorateO,
                                               String[] std) {
        List<String> deOArrayList = new ArrayList<>();
        List<String> deOPartList = new ArrayList<>();
        List<Integer> positions = new ArrayList<>();
        List<DyadPre> rtn = new ArrayList<>();
        int j = 0;
        for (int i = 0; i < wordArray.length; i++) {
            if ("de".equals(partPatternArray[i])) {
                if (deDecorateO.contains(std[i])) {
                    deOArrayList.add(wordArray[i]);
                    deOPartList.add(partPatternArray[i]);
                    j++;
                }
            } else if ("o".equals(partPatternArray[i]) || "oa".equals(partPatternArray[i])) {
                deOArrayList.add(wordArray[i]);
                deOPartList.add(partPatternArray[i]);
                positions.add(j);
                j++;
            }
        }
        for (Integer position : positions) {
            List<String> deOArr = new ArrayList<>();
            List<String> deOPart = new ArrayList<>();
            deOArr.addAll(deOArrayList);
            deOPart.addAll(deOPartList);
            for (int i = positions.size() - 1; i >= 0; i--) {
                if (position != positions.get(i)) {
                    deOArr.remove((int) positions.get(i));
                    deOPart.remove((int) positions.get(i));
                }
            }
            DyadPre ode = new DyadPre();
            ode.setArray(BusinessUtil.getStringFromListBySeparator(deOArr, ","));
            ode.setPartPattern(BusinessUtil.getStringFromListBySeparator(deOPart, ","));
            rtn.add(ode);
        }
        return rtn;
    }

    /**
     * p+o抽取完后有替换元素和p+o合并成o(同时拥有按合成结果) 合并完把std转变为二元组的std为了合并同义词
     *
     * @param wordArray
     * @param partPatternArray
     * @param std
     * @param poMergeRoles2
     * @return
     */
    private Map<String, String> mergePO(String array, String partPattern, String[] std,
                                        List<Map<String, String>> poMergeRoles) {
        String tempArray = "";
        String tempPartPattern = "";
        // 经过规则合并后没有变化了出循环
        while (!StringUtils.equals(tempArray, array) && !StringUtils.equals(tempPartPattern, partPattern)) {
            // 记录进循环时的分词和属性
            tempArray = array;
            tempPartPattern = partPattern;
            // 进行规则循环合并
            for (Map<String, String> poMergeRole : poMergeRoles) {
                String[] wordArray = array.substring(1).split(",");
                String[] partPatternArray = partPattern.substring(1).split(",");
                String[] poArray = poMergeRole.get("array").substring(1).split(",");
                String[] poPartPattern = poMergeRole.get("part_pattern").substring(1).split(",");
                List<Integer> oIndex = new ArrayList<>();
                List<Integer> pIndex = new ArrayList<>();
                int j = 0;
                boolean beginFlag = false;
                if (wordArray.length >= poArray.length) {
                    outterLoop:
                    for (int i = 0; i < poArray.length; ) {
                        for (; j < wordArray.length; j++) {
                            if ("p".equals(partPatternArray[j])) {
                                if (poPartPattern[i].equals(partPatternArray[j]) && poArray[i].equals(wordArray[j])) {
                                    pIndex.add(j);
                                    j++;
                                    beginFlag = true;
                                    break;
                                } else {
                                    if (beginFlag) {
                                        beginFlag = false;
                                        i = 0;
                                        break outterLoop;
                                    }
                                }
                            } else if ("o".equals(partPatternArray[j]) || "oa".equals(partPatternArray[j])) {
                                boolean oOaFlag = false;
                                // o和oa不区分属性
                                if (("o".equals(poPartPattern[i]) || "oa".equals(poPartPattern[i]))
                                        && ("o".equals(partPatternArray[j]) || "oa".equals(partPatternArray[j]))) {
                                    oOaFlag = true;
                                }
                                if ((oOaFlag ? true : poPartPattern[i].equals(partPatternArray[j]))
                                        && poArray[i].equals(wordArray[j])) {
                                    oIndex.add(j);
                                    j++;
                                    beginFlag = true;
                                    break;
                                } else {
                                    if (beginFlag) {
                                        beginFlag = false;
                                        i = 0;
                                        continue outterLoop;
                                    }
                                }
                            }
                        }
                        i++;
                    }
                }
                // 规则匹配成功
                if (oIndex.size() > 0 && pIndex.size() > 0 && poArray.length == (oIndex.size() + pIndex.size())) {
                    List<String> wordList = CollectionUtil.getListByArray(wordArray);
                    List<String> partPatternList = CollectionUtil.getListByArray(partPatternArray);
                    List<String> stdList = CollectionUtil.getListByArray(std);
                    // 把o下标的数据进行替换
                    wordList.remove((int) oIndex.get(0));
                    wordList.add((int) oIndex.get(0), poMergeRole.get("array").replace(",", ""));
                    stdList.remove((int) oIndex.get(0));
                    stdList.add((int) oIndex.get(0), poMergeRole.get("std").replace(",", ""));
                    // 把p下标中的数据清空
                    for (int i = (pIndex.size() - 1); i >= 0; i--) {
                        wordList.remove((int) pIndex.get(i));
                        partPatternList.remove((int) pIndex.get(i));
                        stdList.remove((int) pIndex.get(i));
                    }
                    array = BusinessUtil.getStringFromListBySeparator(wordList, ",");
                    partPattern = BusinessUtil.getStringFromListBySeparator(partPatternList, ",");
                    std = BusinessUtil.getStringFromListBySeparator(stdList, ",").substring(1).split(",");
                }
            }
        }
        Map<String, String> rtn = new HashMap<>();
        rtn.put("array", array);
        rtn.put("partPattern", partPattern);
        rtn.put("std", BusinessUtil.getStringFromListBySeparator(CollectionUtil.getListByArray(std), ","));
        return rtn;
    }

    /**
     * 根据词语的列表获取根据逗号分割的字符串
     *
     * @param pTemp
     * @return
     */
    private String getWordStrByList(List<String> pTemp) {
        if (pTemp.isEmpty()) {
            return "";
        }

        StringBuilder sb = new StringBuilder(",");
        for (String p : pTemp) {
            sb.append(p);
            sb.append(",");
        }
        return sb.toString();
    }

    /**
     * 根据p和o的词语以及相关属性获取最终p+o的数据
     *
     * @param pTemp
     * @param oTemp
     * @param splitFlag
     * @param position:1表示p在o之前；2表示p在o之后
     * @param complex
     * @param oStdTemp
     * @param pStdTemp
     * @return
     */
    private List<DyadPre> getPOListByWords(List<String> pTemp, String oTemp, String oPropertyTemp, boolean splitFlag,
                                           int position, List<String> pStdTemp, String oStdTemp, List<String> wrongPPList) {
        List<String> ppStrList = new ArrayList<>();
        List<String> ppStdStrList = new ArrayList<>();

        if (!splitFlag || pTemp.size() == 1 || !wrongPPList.contains(getWordStrByList(pTemp))) {
            ppStrList.add(getWordStrByList(pTemp));
            ppStdStrList.add(getWordStrByList(pStdTemp));
        } else if (pTemp.size() > 1) {
            for (int i = 1; i <= pTemp.size(); i++) {
                if (position == 1) {
                    ppStrList.add(getWordStrByList(pTemp.subList(pTemp.size() - i, pTemp.size())));
                    ppStdStrList.add(getWordStrByList(pStdTemp.subList(pStdTemp.size() - i, pStdTemp.size())));
                } else {
                    ppStrList.add(getWordStrByList(pTemp.subList(0, i)));
                    ppStdStrList.add(getWordStrByList(pStdTemp.subList(0, i)));
                }
            }
        }

        List<DyadPre> resultList = new ArrayList<>();
        for (int i = 0; i < ppStrList.size(); i++) {
            String pp = ppStrList.get(i);
            String ppStd = ppStdStrList.get(i);

            DyadPre temp = new DyadPre();
            temp.setArray(position == 1 ? pp + oTemp + "," : "," + oTemp + pp);
            String partPattern = ",";
            for (int j = 0; j < pp.length() - pp.replace(",", "").length() - 1; j++) {
                partPattern += "p,";
            }
            temp.setPartPattern(position == 1 ? partPattern + oPropertyTemp + "," : "," + oPropertyTemp + partPattern);
            temp.setOrderVocabulary(oStdTemp);
            temp.setStdArray(position == 1 ? ppStd + oStdTemp + "," : "," + oStdTemp + ppStd);
            temp.setStdSynonym(temp.getStdArray());
            temp.setType("p+o");

            resultList.add(temp);
        }

        return resultList;
    }

    /**
     * 根据一个复杂的p+o拆解出单个p+o的列表
     *
     * @param complex
     * @param wrongPPList
     * @return
     */
    private List<DyadPre> getPOPreByComplex(String[] words, String[] properties, String[] stds,
                                            List<String> wrongPPList) {

        List<DyadPre> list = new ArrayList<>();
        boolean splitFlag = false;
        List<String> pTemp = new ArrayList<>();
        List<String> pStdTemp = new ArrayList<>();
        String oTemp = "";
        String oStdTemp = "";
        String oPropertyTemp = "";

        for (int i = 0; i < words.length; i++) {
            if (properties[i].equals("p")) {
                // 属性是p的元素则累加，并判断该当前p+p是否是错误的
                pTemp.add(words[i]);
                pStdTemp.add(stds[i]);
                if (!splitFlag && wrongPPList.contains(getWordStrByList(pTemp))) {
                    splitFlag = true;
                }

                // 如果p是最后一个词语了则需维护最后一个p+o
                if (i == words.length - 1) {
                    list.addAll(
                            getPOListByWords(pTemp, oTemp, oPropertyTemp, false, 2, pStdTemp, oStdTemp, wrongPPList));
                }
            } else if ("o".equals(properties[i]) || "oa".equals(properties[i])) {
                // 属性是o或者oa，如果有上一个o和p则先维护
                if (!oTemp.isEmpty() && !pTemp.isEmpty()) {
                    list.addAll(getPOListByWords(pTemp, oTemp, oPropertyTemp, splitFlag, 2, pStdTemp, oStdTemp,
                            wrongPPList));
                }

                // 如果p+p之前没有o，则多个p不需要拆分
                if (oTemp.isEmpty()) {
                    splitFlag = false;
                }

                // 将属性修改为当前的o
                oTemp = words[i];
                oStdTemp = stds[i];
                oPropertyTemp = properties[i];

                // 如果之前有p则维护当前o的p+o
                if (!pTemp.isEmpty()) {
                    list.addAll(getPOListByWords(pTemp, oTemp, oPropertyTemp, splitFlag, 1, pStdTemp, oStdTemp,
                            wrongPPList));
                }

                // 维护好之后清空之前的p
                pTemp = new ArrayList<>();
                pStdTemp = new ArrayList<>();
                splitFlag = true;
            }
        }
        return list;
    }

    /**
     * 抽取p+o,相邻的p相邻的p+(单独o)或(单独o)+p
     *
     * @param wordArray
     * @param partPatternArray
     * @param wrongPPList
     * @return
     */
    private List<DyadPre> extractPO(String[] wordArray, String[] partPatternArray, String[] std,
                                    List<String> wrongPPList) {
        List<String> wordList = new ArrayList<>();
        List<String> propertyList = new ArrayList<>();
        for (int i = 0; i < wordArray.length; i++) {
            if ("p".equals(partPatternArray[i]) || "o".equals(partPatternArray[i])
                    || "oa".equals(partPatternArray[i])) {
                wordList.add(wordArray[i]);
                propertyList.add(partPatternArray[i]);
            }
        }
        // p+o通过代码拆分生成
        List<DyadPre> resultList = new ArrayList<>();
        resultList.addAll(getPOPreByComplex(wordList.toArray(new String[0]), propertyList.toArray(new String[0]), std,
                wrongPPList));
        return resultList;
    }

    /**
     * 抽取连续的整个的p,p,p 二元组p+p
     *
     * @param array
     * @param partPattern
     * @return
     */
    private List<DyadPre> extractP(String[] wordArray, String[] partPatternArray) {
        List<String> wordList = new ArrayList<>();
        List<String> propertyList = new ArrayList<>();
        List<DyadPre> rtn = new ArrayList<>();
        for (int i = 0; i < wordArray.length; i++) {
            if ("p".equals(partPatternArray[i])) {
                wordList.add(wordArray[i]);
                propertyList.add(partPatternArray[i]);
            } else {
                if (wordList != null && wordList.size() > 1 && propertyList != null && propertyList.size() > 1) {
                    DyadPre pp = new DyadPre();
                    pp.setArray(BusinessUtil.getStringFromListBySeparator(wordList, ","));
                    pp.setPartPattern(BusinessUtil.getStringFromListBySeparator(propertyList, ","));
                    pp.setType("p+p");
                    rtn.add(pp);
                    wordList = new ArrayList<>();
                    propertyList = new ArrayList<>();
                } else {
                    wordList = new ArrayList<>();
                    propertyList = new ArrayList<>();
                }
            }
        }
        return rtn;
    }

    /**
     * 替换词语和拆分词语替换
     *
     * @param replaceMap
     * @param array
     * @param partPattern
     * @return
     */
    private Map<String, String> replaceVocab(Map<String, Map<String, String>> replaceMap, String[] wordArray,
                                             String[] partPatternArray) {
        Map<String, String> rtn = new HashMap<>();
        for (int i = 0; i < wordArray.length; i++) {
            if (replaceMap.get(partPatternArray[i]) != null) {
                Map<String, String> replace = replaceMap.get(partPatternArray[i]);
                if (replace.get(wordArray[i]) != null) {
                    String[] result = replace.get(wordArray[i]).split("\t");
                    wordArray[i] = result[0];
                    partPatternArray[i] = result[1];
                }
            }
        }
        rtn.put("array", BusinessUtil.getStringFromListBySeparator(CollectionUtil.getListByArray(wordArray), ","));
        rtn.put("partPattern",
                BusinessUtil.getStringFromListBySeparator(CollectionUtil.getListByArray(partPatternArray), ","));
        return rtn;
    }

    /**
     * 获取替换和拆分词语的map
     *
     * @return
     */
    private Map<String, Map<String, String>> getReplaceMap() {
        Map<String, Map<String, String>> replaceMap = new HashMap<>();
        // 获取替换词
        List<Map<String, String>> replaceList = vocabElementDao.retrieveElementReplace();
        // 获取拆分
        List<Map<String, String>> splitList = vocabElementDao.retrieveElementSplit();
        replaceList.addAll(splitList);
        for (Map<String, String> replace : replaceList) {
            String[] original = replace.get("original").split("\t");
            String result = replace.get("result");
            if (replaceMap.get(original[1]) == null) {
                Map<String, String> value = new HashMap<>();
                value.put(original[0], result);
                replaceMap.put(original[1], value);
            } else {
                Map<String, String> value = replaceMap.get(original[1]);
                value.put(original[0], result);
            }
        }
        return replaceMap;
    }

    /**
     * 判断是否符合含有该类属性
     *
     * @param partPattern
     * @param string
     * @return
     */

    private boolean checkProperty(String partPattern, String type) {
        String[] types = type.split(",");
        for (String property : types) {
            if ("o".equals(property) && !partPattern.contains("," + property + ",") && !partPattern.contains(",oa,")) {
                return false;
            } else if (!partPattern.contains("," + property + ",")) {
                return false;
            }
        }
        return true;
    }

    /**
     * 正常抽取si+de,s+de 先要抽取单个de,再抽取多个进行校验(抽取时,全部抽取在之后进行校验) de1,o,de2,de3,s, --->
     * de1,s de2,s de3,s de1,de2,de3,s
     *
     * @param type
     * @param array
     * @param partPattern
     * @return
     */
    private List<DyadPre> extractDe(String type, String[] wordArray, String[] partPatternArray) {
        List<String> wordList = new ArrayList<>();
        List<String> propertyList = new ArrayList<>();
        List<DyadPre> rtn = new ArrayList<>();
        for (int i = 0; i < wordArray.length; i++) {
            if ("de".equals(partPatternArray[i]) || type.equals(partPatternArray[i])) {
                wordList.add(wordArray[i]);
                propertyList.add(partPatternArray[i]);
            }
        }
        if (wordList.size() > 0 && propertyList.size() > 0) {
            // 抽取所有的de和s,de和si 个数>2的时候才会出现需要单独抽取整个的二元组
            if (wordList.size() > 2) {
                DyadPre all = new DyadPre();
                all.setArray(BusinessUtil.getStringFromListBySeparator(wordList, ","));
                all.setPartPattern(BusinessUtil.getStringFromListBySeparator(propertyList, ","));
                all.setType(type + "+de");
                rtn.add(all);
            }
            // 抽取单个的de+s,de+si
            for (int i = 0; i < wordList.size(); i++) {
                String word = wordList.get(i);
                String property = propertyList.get(i);
                for (int j = i + 1; j < wordList.size(); j++) {
                    if (!property.equals(propertyList.get(j))) {
                        DyadPre pre = new DyadPre();
                        pre.setArray("," + word + "," + wordList.get(j) + ",");
                        pre.setPartPattern("," + property + "," + propertyList.get(j) + ",");
                        pre.setType(type + "+de");
                        rtn.add(pre);
                    }
                }
            }
        }
        return rtn;
    }
}
